from tkinter import *
import tkinter.messagebox
from tkinter import ttk
from tkinter import font
from src.backend.billing_b import BillingBackend

class BillingFrontend:
    """Frontend UI for billing management"""
    
    def __init__(self, master, user_type='admin'):
        self.master = master
        self.user_type = user_type
        self.backend = BillingBackend()
        
        self.master.title("HOSPITAL MANAGEMENT SYSTEM")
        self.master.geometry("1500x700+0+0")
        self.master.config(bg="#C0C0C0")
        self.frame = Frame(self.master, bg="#C0C0C0")
        self.frame.pack()

        #=============ATTRIBUTES===========
        self.invoice_id = IntVar()
        self.patient_id = IntVar()
        self.appointment_id = IntVar()
        self.invoice_date = StringVar()
        self.due_date = StringVar()
        self.subtotal = StringVar()
        self.tax_amount = StringVar()
        self.total_amount = StringVar()
        self.status = StringVar()

        self.create_ui()

    def create_ui(self):
        """Create the user interface"""
        #===============TITLE==========
        self.lblTitle = Label(self.frame, text="BILLING WINDOW", font="Arial 16 bold", bg="#C0C0C0", fg="#000080")
        self.lblTitle.grid(row=0, column=0, columnspan=2, pady=25)
        
        #==============FRAME==========
        self.LoginFrame = Frame(self.frame, width=400, height=80, relief="ridge", bg="#C0C0C0", bd=20)
        self.LoginFrame.grid(row=1, column=0)
        
        self.LoginFrame2 = Frame(self.frame, width=400, height=80, relief="ridge", bg="#C0C0C0", bd=20)
        self.LoginFrame2.grid(row=2, column=0)
        
        self.create_form_fields()
        self.create_buttons()

    def create_form_fields(self):
        """Create form input fields"""
        #===========LABELS=============
        self.lblinvid = Label(self.LoginFrame, text="INVOICE ID", font="Arial 11 bold", bg="#C0C0C0", bd=22)
        self.lblinvid.grid(row=0, column=0, sticky=W, padx=5, pady=5)
        self.lblinvid = Entry(self.LoginFrame, font="Arial 11 bold", bd=2, relief="sunken", textvariable=self.invoice_id)
        self.lblinvid.grid(row=0, column=1, padx=5, pady=5)
        
        self.lblpid = Label(self.LoginFrame, text="PATIENT ID", font="Arial 11 bold", bg="#C0C0C0", bd=22)
        self.lblpid.grid(row=1, column=0, sticky=W, padx=5, pady=5)
        self.lblpid = Entry(self.LoginFrame, font="Arial 11 bold", bd=2, relief="sunken", textvariable=self.patient_id)
        self.lblpid.grid(row=1, column=1, padx=5, pady=5)
        
        self.lblappid = Label(self.LoginFrame, text="APPOINTMENT ID", font="Arial 11 bold", bg="#C0C0C0", bd=22)
        self.lblappid.grid(row=2, column=0, sticky=W, padx=5, pady=5)
        self.lblappid = Entry(self.LoginFrame, font="Arial 11 bold", bd=2, relief="sunken", textvariable=self.appointment_id)
        self.lblappid.grid(row=2, column=1, padx=5, pady=5)
        
        self.lblinvdate = Label(self.LoginFrame, text="INVOICE DATE (YYYY-MM-DD)", font="Arial 11 bold", bg="#C0C0C0", bd=22)
        self.lblinvdate.grid(row=3, column=0, sticky=W, padx=5, pady=5)
        self.lblinvdate = Entry(self.LoginFrame, font="Arial 11 bold", bd=2, relief="sunken", textvariable=self.invoice_date)
        self.lblinvdate.grid(row=3, column=1, padx=5, pady=5)
        
        self.lblduedate = Label(self.LoginFrame, text="DUE DATE (YYYY-MM-DD)", font="Arial 11 bold", bg="#C0C0C0", bd=22)
        self.lblduedate.grid(row=4, column=0, sticky=W, padx=5, pady=5)
        self.lblduedate = Entry(self.LoginFrame, font="Arial 11 bold", bd=2, relief="sunken", textvariable=self.due_date)
        self.lblduedate.grid(row=4, column=1, padx=5, pady=5)
        
        self.lblsubtotal = Label(self.LoginFrame, text="SUBTOTAL ₹", font="Arial 11 bold", bg="#C0C0C0", bd=22)
        self.lblsubtotal.grid(row=0, column=2)
        self.lblsubtotal = Entry(self.LoginFrame, font="Arial 11 bold", bd=2, textvariable=self.subtotal)
        self.lblsubtotal.grid(row=0, column=3)
        
        self.lbltax = Label(self.LoginFrame, text="TAX AMOUNT ₹", font="Arial 11 bold", bg="#C0C0C0", bd=22)
        self.lbltax.grid(row=1, column=2)
        self.lbltax = Entry(self.LoginFrame, font="Arial 11 bold", bd=2, textvariable=self.tax_amount)
        self.lbltax.grid(row=1, column=3)
        
        self.lbltotal = Label(self.LoginFrame, text="TOTAL AMOUNT ₹", font="Arial 11 bold", bg="#C0C0C0", bd=22)
        self.lbltotal.grid(row=2, column=2)
        self.lbltotal = Entry(self.LoginFrame, font="Arial 11 bold", bd=2, textvariable=self.total_amount)
        self.lbltotal.grid(row=2, column=3)
        
        self.lblstatus = Label(self.LoginFrame, text="STATUS", font="Arial 11 bold", bg="#C0C0C0", bd=22)
        self.lblstatus.grid(row=3, column=2)
        self.lblstatus = Entry(self.LoginFrame, font="Arial 11 bold", bd=2, textvariable=self.status)
        self.lblstatus.grid(row=3, column=3)

    def create_buttons(self):
        """Create action buttons"""
        #===========BUTTONS=============    
        self.button3 = Button(self.LoginFrame2, text="UPDATE DATA", width=15, font="Arial 11 bold", bg="#C0C0C0", relief="raised", bd=2, command=self.UPDATE_DATA)
        self.button3.grid(row=3, column=2, padx=5, pady=5)
        
        self.button3 = Button(self.LoginFrame2, text="GENERATE BILL", width=15, font="Arial 11 bold", bg="#C0C0C0", relief="raised", bd=2, command=self.GEN_BILL)
        self.button3.grid(row=3, column=3, padx=5, pady=5)
     
        self.button6 = Button(self.LoginFrame2, text="EXIT", width=10, font="Arial 11 bold", bg="#C0C0C0", relief="raised", bd=2, command=self.Exit)
        self.button6.grid(row=3, column=4, padx=5, pady=5)
        
        if self.user_type == 'root':
            self.btn_global = Button(self.LoginFrame2, text="GLOBAL SEARCH", width=15, font="Arial 11 bold", bg="#C0C0C0", relief="raised", bd=2, command=self.GLOBAL_BILL)
            self.btn_global.grid(row=4, column=1, columnspan=2, pady=10)

    #FUNCTION TO UPDATE DATA IN BILLING FORM 
    def UPDATE_DATA(self):
        try:
            invoice_id = self.invoice_id.get()
            
            # If invoice_id is provided, update existing invoice; otherwise add new
            if invoice_id:
                # Update existing invoice
                update_data = {}
                if self.patient_id.get():
                    update_data['patient_id'] = self.patient_id.get()
                if self.appointment_id.get():
                    update_data['appointment_id'] = self.appointment_id.get()
                if self.invoice_date.get().strip():
                    update_data['invoice_date'] = self.invoice_date.get().strip()
                if self.due_date.get().strip():
                    update_data['due_date'] = self.due_date.get().strip()
                if self.subtotal.get().strip():
                    update_data['subtotal'] = float(self.subtotal.get().strip())
                if self.tax_amount.get().strip():
                    update_data['tax_amount'] = float(self.tax_amount.get().strip())
                if self.total_amount.get().strip():
                    update_data['total_amount'] = float(self.total_amount.get().strip())
                if self.status.get().strip():
                    update_data['status'] = self.status.get().strip()
                
                if not update_data:
                    tkinter.messagebox.showerror("HOSPITAL DATABASE SYSTEM", "No data to update")
                    return
                
                if self.backend.update_invoice(invoice_id, update_data):
                    tkinter.messagebox.showinfo("HOSPITAL DATABASE SYSTEM", "Invoice updated successfully")
                    self.clear_form()
                else:
                    tkinter.messagebox.showerror("HOSPITAL DATABASE SYSTEM", "Failed to update invoice")
            else:
                # Add new invoice
                invoice_data = {
                    'patient_id': self.patient_id.get(),
                    'appointment_id': self.appointment_id.get(),
                    'invoice_date': self.invoice_date.get().strip(),
                    'due_date': self.due_date.get().strip(),
                    'subtotal': self.subtotal.get().strip(),
                    'tax_amount': self.tax_amount.get().strip(),
                    'total_amount': self.total_amount.get().strip(),
                    'status': self.status.get().strip()
                }
                
                # Validate data
                is_valid, message = self.backend.validate_invoice_data(invoice_data)
                if not is_valid:
                    tkinter.messagebox.showerror("HOSPITAL DATABASE SYSTEM", message)
                    return
                
                # Convert string values to appropriate types
                invoice_data['patient_id'] = int(invoice_data['patient_id'])
                invoice_data['appointment_id'] = int(invoice_data['appointment_id'])
                invoice_data['subtotal'] = float(invoice_data['subtotal'])
                invoice_data['total_amount'] = float(invoice_data['total_amount'])
                
                if invoice_data['tax_amount']:
                    invoice_data['tax_amount'] = float(invoice_data['tax_amount'])
                else:
                    invoice_data['tax_amount'] = 0
                
                if not invoice_data['status']:
                    invoice_data['status'] = 'pending'
                
                # Add invoice to database
                if self.backend.add_invoice(invoice_data):
                    tkinter.messagebox.showinfo("HOSPITAL DATABASE SYSTEM", "Invoice added successfully")
                    self.clear_form()
                else:
                    tkinter.messagebox.showerror("HOSPITAL DATABASE SYSTEM", "Failed to add invoice")
                
        except Exception as e:
            tkinter.messagebox.showerror("HOSPITAL DATABASE SYSTEM", f"Error: {str(e)}")
            
    #FUNCTION TO GENERATE BILL IN BILLING FORM 
    def GEN_BILL(self):
        try:
            # Get form data
            patient_id = self.patient_id.get()
            appointment_id = self.appointment_id.get()
            invoice_date = self.invoice_date.get().strip()
            due_date = self.due_date.get().strip()
            subtotal = self.subtotal.get().strip()
            tax_amount = self.tax_amount.get().strip()
            total_amount = self.total_amount.get().strip()
            status = self.status.get().strip()
            
            # Validate required fields
            if not all([patient_id, appointment_id, invoice_date, due_date, subtotal, total_amount]):
                tkinter.messagebox.showerror("HOSPITAL DATABASE SYSTEM", "Please fill in all required fields")
                return
            
            # Calculate tax if not provided
            if not tax_amount:
                try:
                    subtotal_val = float(subtotal)
                    tax_amount = str(self.backend.calculate_tax(subtotal_val))
                except ValueError:
                    tax_amount = "0"
            
            # Calculate total if not provided
            if not total_amount:
                try:
                    subtotal_val = float(subtotal)
                    tax_val = float(tax_amount)
                    total_amount = str(self.backend.calculate_total(subtotal_val, tax_val))
                except ValueError:
                    total_amount = subtotal
            
            # Set default status if not provided
            if not status:
                status = "pending"
            
            # Show bill preview
            tkinter.messagebox.showinfo("HOSPITAL DATABASE SYSTEM", 
                f"Bill generated:\nPatient ID: {patient_id}\nAppointment ID: {appointment_id}\nSubtotal: ₹{subtotal}\nTax: ₹{tax_amount}\nTotal: ₹{total_amount}\nStatus: {status}")
            
            # Clear form
            self.clear_form()
            
        except Exception as e:
            tkinter.messagebox.showerror("HOSPITAL DATABASE SYSTEM", f"Error: {str(e)}")
    
    def clear_form(self):
        """Clear all form fields"""
        self.invoice_id.set(0)
        self.patient_id.set(0)
        self.appointment_id.set(0)
        self.invoice_date.set("")
        self.due_date.set("")
        self.subtotal.set("")
        self.tax_amount.set("")
        self.total_amount.set("")
        self.status.set("") 

    #FUNCTION TO EXIT BILLING WINDOW       
    def Exit(self):            
        self.master.destroy()
    
    def GLOBAL_BILL(self):
        """Open global billing search window with full CRUD functionality"""
        self.newWindow = Toplevel(self.master)
        self.app = GlobalBillingSearchMenu(self.newWindow, self.backend)

#CLASS FOR GLOBAL BILLING SEARCH MENU (ROOT ONLY)
class GlobalBillingSearchMenu:
    def __init__(self, master, backend):    
        self.master = master
        self.backend = backend
        self.master.title("GLOBAL SEARCH - ALL INVOICES")
        self.master.geometry("1200x600+0+0")
        self.master.config(bg="#C0C0C0")
        self.frame = Frame(self.master, bg="#C0C0C0")
        self.frame.pack()
        
        self.lblTitle = Label(self.frame, text="GLOBAL BILLING SEARCH", font="Arial 16 bold", bg="#C0C0C0", fg="#000080")
        self.lblTitle.grid(row=0, column=0, columnspan=2, pady=25)
        
        # Create Treeview for displaying all invoices
        self.tree_frame = Frame(self.frame, bg="#C0C0C0")
        self.tree_frame.grid(row=1, column=0, padx=20, pady=10)
        
        # Define columns
        columns = ('Invoice ID', 'Patient ID', 'Appointment ID', 'Invoice Date', 'Due Date', 'Subtotal', 'Tax', 'Total', 'Status')
        self.tree = ttk.Treeview(self.tree_frame, columns=columns, show='headings', height=15)
        
        # Define headings
        for col in columns:
            self.tree.heading(col, text=col)
            self.tree.column(col, width=120)
        
        # Add scrollbar
        scrollbar = ttk.Scrollbar(self.tree_frame, orient=VERTICAL, command=self.tree.yview)
        self.tree.configure(yscrollcommand=scrollbar.set)
        
        # Pack treeview and scrollbar
        self.tree.pack(side=LEFT, fill=BOTH, expand=True)
        scrollbar.pack(side=RIGHT, fill=Y)
        
        # Buttons frame
        self.button_frame = Frame(self.frame, bg="#C0C0C0")
        self.button_frame.grid(row=2, column=0, pady=10)
        
        self.refresh_btn = Button(self.button_frame, text="REFRESH", width=15, font="Arial 11 bold", 
                                bg="#C0C0C0", relief="raised", bd=2, command=self.refresh_data)
        self.refresh_btn.pack(side=LEFT, padx=5)
        
        self.edit_btn = Button(self.button_frame, text="EDIT SELECTED", width=15, font="Arial 11 bold", 
                              bg="#C0C0C0", relief="raised", bd=2, command=self.edit_selected)
        self.edit_btn.pack(side=LEFT, padx=5)
        
        self.delete_btn = Button(self.button_frame, text="DELETE SELECTED", width=15, font="Arial 11 bold", 
                                bg="#C0C0C0", relief="raised", bd=2, command=self.delete_selected)
        self.delete_btn.pack(side=LEFT, padx=5)
        
        self.close_btn = Button(self.button_frame, text="CLOSE", width=15, font="Arial 11 bold", 
                               bg="#C0C0C0", relief="raised", bd=2, command=self.close_window)
        self.close_btn.pack(side=LEFT, padx=5)
        
        # Load initial data
        self.refresh_data()
    
    def refresh_data(self):
        """Refresh the billing data in the treeview"""
        try:
            # Clear existing data
            for item in self.tree.get_children():
                self.tree.delete(item)
            
            # Get all invoices from database
            invoices = self.backend.get_all_invoices()
            
            # Insert data into treeview
            for invoice in invoices:
                self.tree.insert('', 'end', values=(
                    invoice[0],  # Invoice ID
                    invoice[1],  # Patient ID
                    invoice[2],  # Appointment ID
                    str(invoice[3]),  # Invoice Date
                    str(invoice[4]),  # Due Date
                    invoice[5],  # Subtotal
                    invoice[6],  # Tax
                    invoice[7],  # Total
                    invoice[8]   # Status
                ))
                
        except Exception as e:
            tkinter.messagebox.showerror("HOSPITAL DATABASE SYSTEM", f"Error loading data: {str(e)}")
    
    def edit_selected(self):
        """Edit the selected invoice"""
        selection = self.tree.selection()
        if not selection:
            tkinter.messagebox.showwarning("HOSPITAL DATABASE SYSTEM", "Please select an invoice to edit")
            return
        
        # Get selected invoice data
        item = self.tree.item(selection[0])
        invoice_id = item['values'][0]
        
        # Open edit window
        self.edit_window = Toplevel(self.master)
        self.edit_app = EditInvoiceWindow(self.edit_window, invoice_id, self.backend, self.refresh_data)
    
    def delete_selected(self):
        """Delete the selected invoice"""
        selection = self.tree.selection()
        if not selection:
            tkinter.messagebox.showwarning("HOSPITAL DATABASE SYSTEM", "Please select an invoice to delete")
            return
        
        # Get selected invoice data
        item = self.tree.item(selection[0])
        invoice_id = item['values'][0]
        patient_id = item['values'][1]
        
        # Confirm deletion
        result = tkinter.messagebox.askyesno("HOSPITAL DATABASE SYSTEM", 
                                           f"Are you sure you want to delete invoice {invoice_id} for patient {patient_id}?")
        if result:
            try:
                if self.backend.delete_invoice(invoice_id):
                    tkinter.messagebox.showinfo("HOSPITAL DATABASE SYSTEM", "Invoice deleted successfully")
                    self.refresh_data()
                else:
                    tkinter.messagebox.showerror("HOSPITAL DATABASE SYSTEM", "Failed to delete invoice")
            except Exception as e:
                tkinter.messagebox.showerror("HOSPITAL DATABASE SYSTEM", f"Error: {str(e)}")
    
    def close_window(self):
        """Close the global search window"""
        self.master.destroy()

#CLASS FOR EDIT INVOICE WINDOW
class EditInvoiceWindow:
    def __init__(self, master, invoice_id, backend, refresh_callback):
        self.master = master
        self.invoice_id = invoice_id
        self.backend = backend
        self.refresh_callback = refresh_callback
        
        self.master.title("EDIT INVOICE")
        self.master.geometry("800x600+0+0")
        self.master.config(bg="#C0C0C0")
        self.frame = Frame(self.master, bg="#C0C0C0")
        self.frame.pack()
        
        # Get invoice data
        self.invoice = self.backend.get_invoice(invoice_id)
        if not self.invoice:
            tkinter.messagebox.showerror("HOSPITAL DATABASE SYSTEM", "Invoice not found")
            self.master.destroy()
            return
        
        # Create form variables
        self.patient_id = IntVar(value=self.invoice[1])
        self.appointment_id = IntVar(value=self.invoice[2])
        self.invoice_date = StringVar(value=str(self.invoice[3]))
        self.due_date = StringVar(value=str(self.invoice[4]))
        self.subtotal = StringVar(value=str(self.invoice[5]))
        self.tax_amount = StringVar(value=str(self.invoice[6]))
        self.total_amount = StringVar(value=str(self.invoice[7]))
        self.status = StringVar(value=self.invoice[8])
        
        # Title
        self.lblTitle = Label(self.frame, text="EDIT INVOICE", font="Arial 16 bold", bg="#C0C0C0", fg="#000080")
        self.lblTitle.grid(row=0, column=0, columnspan=2, pady=20)
        
        # Form frame
        self.form_frame = Frame(self.frame, bg="#C0C0C0")
        self.form_frame.grid(row=1, column=0, padx=20, pady=10)
        
        # Form fields
        row = 0
        Label(self.form_frame, text="INVOICE ID:", font="Arial 11 bold", bg="#C0C0C0").grid(row=row, column=0, sticky=W, pady=5)
        Label(self.form_frame, text=invoice_id, font="Arial 11", bg="#C0C0C0").grid(row=row, column=1, pady=5)
        row += 1
        
        Label(self.form_frame, text="PATIENT ID:", font="Arial 11 bold", bg="#C0C0C0").grid(row=row, column=0, sticky=W, pady=5)
        Entry(self.form_frame, textvariable=self.patient_id, font="Arial 11", width=30).grid(row=row, column=1, pady=5)
        row += 1
        
        Label(self.form_frame, text="APPOINTMENT ID:", font="Arial 11 bold", bg="#C0C0C0").grid(row=row, column=0, sticky=W, pady=5)
        Entry(self.form_frame, textvariable=self.appointment_id, font="Arial 11", width=30).grid(row=row, column=1, pady=5)
        row += 1
        
        Label(self.form_frame, text="INVOICE DATE (YYYY-MM-DD):", font="Arial 11 bold", bg="#C0C0C0").grid(row=row, column=0, sticky=W, pady=5)
        Entry(self.form_frame, textvariable=self.invoice_date, font="Arial 11", width=30).grid(row=row, column=1, pady=5)
        row += 1
        
        Label(self.form_frame, text="DUE DATE (YYYY-MM-DD):", font="Arial 11 bold", bg="#C0C0C0").grid(row=row, column=0, sticky=W, pady=5)
        Entry(self.form_frame, textvariable=self.due_date, font="Arial 11", width=30).grid(row=row, column=1, pady=5)
        row += 1
        
        Label(self.form_frame, text="SUBTOTAL:", font="Arial 11 bold", bg="#C0C0C0").grid(row=row, column=0, sticky=W, pady=5)
        Entry(self.form_frame, textvariable=self.subtotal, font="Arial 11", width=30).grid(row=row, column=1, pady=5)
        row += 1
        
        Label(self.form_frame, text="TAX AMOUNT:", font="Arial 11 bold", bg="#C0C0C0").grid(row=row, column=0, sticky=W, pady=5)
        Entry(self.form_frame, textvariable=self.tax_amount, font="Arial 11", width=30).grid(row=row, column=1, pady=5)
        row += 1
        
        Label(self.form_frame, text="TOTAL AMOUNT:", font="Arial 11 bold", bg="#C0C0C0").grid(row=row, column=0, sticky=W, pady=5)
        Entry(self.form_frame, textvariable=self.total_amount, font="Arial 11", width=30).grid(row=row, column=1, pady=5)
        row += 1
        
        Label(self.form_frame, text="STATUS:", font="Arial 11 bold", bg="#C0C0C0").grid(row=row, column=0, sticky=W, pady=5)
        Entry(self.form_frame, textvariable=self.status, font="Arial 11", width=30).grid(row=row, column=1, pady=5)
        
        # Buttons
        self.button_frame = Frame(self.frame, bg="#C0C0C0")
        self.button_frame.grid(row=2, column=0, pady=20)
        
        Button(self.button_frame, text="SAVE", width=15, font="Arial 11 bold", 
               bg="#C0C0C0", relief="raised", bd=2, command=self.save_changes).pack(side=LEFT, padx=5)
        Button(self.button_frame, text="CANCEL", width=15, font="Arial 11 bold", 
               bg="#C0C0C0", relief="raised", bd=2, command=self.master.destroy).pack(side=LEFT, padx=5)
    
    def save_changes(self):
        """Save the changes to the invoice"""
        try:
            update_data = {
                'patient_id': self.patient_id.get(),
                'appointment_id': self.appointment_id.get(),
                'invoice_date': self.invoice_date.get().strip(),
                'due_date': self.due_date.get().strip(),
                'subtotal': float(self.subtotal.get().strip()),
                'tax_amount': float(self.tax_amount.get().strip()),
                'total_amount': float(self.total_amount.get().strip()),
                'status': self.status.get().strip()
            }
            
            if self.backend.update_invoice(self.invoice_id, update_data):
                tkinter.messagebox.showinfo("HOSPITAL DATABASE SYSTEM", "Invoice updated successfully")
                self.refresh_callback()
                self.master.destroy()
            else:
                tkinter.messagebox.showerror("HOSPITAL DATABASE SYSTEM", "Failed to update invoice")
                
        except Exception as e:
            tkinter.messagebox.showerror("HOSPITAL DATABASE SYSTEM", f"Error: {str(e)}")

